#ifndef evaluator_c
#define evaluator_c
/*typedef struct {*/
/*	string arg[MaxArg];*/
/*	int nArg;*/
/*	} arguments;*/
// gcc -o evaluator evaluator.c driver_evaluator.c mesinkata.c mesinkar.c worksheet.c worksheetmanager.c eval_proc.c displayTab.c custom_string.c -lm
#include "worksheet.h"
#include "custom_string.h"
#include "eval_proc.h"
#include "evaluator.h"
#include "mesinkata.h"

#define MaxArg 100

#define debug 0
//SET 1 UNTUK MENAMPILKAN DEBUG

#define TF(x) x? "TRUE" : "FALSE"

string eval (string s, Sheet Sh)
/* mengembalikan hasil evaluasi dari string s*/
{	
	string temp;
	static string temp2;
	int i;
	temp=MakeFormula(s);
	temp2=recursive_eval(temp, Sh);
	
	return temp2;
}

boolean isCell (string s)
/* mengecek apakah s menyatakan suatu cell 
misal : A4, B5 */
{	
	if(debug) printf("  isCell (%s) : ",s.s);
	int i = 0;
	boolean retval = 1;
	s=UpperCase(s);
	
	while (s.s[i]>='A' && s.s[i]<='Z') {
		i++;
		}
	if(i==0) {retval=0;}
	if (!(s.s[i] >= '0' && s.s[i] <= '9')) {
		retval=0;
		}
		
        if (retval) {
        	while (i < s.length) {
		        retval = retval && (s.s[i] >= '0' && s.s[i] <= '9');
		        i++;
        	}
        }

	if(debug) printf("%s\n",TF(retval));
	return retval;
}

boolean isArea (string s)
/* mengecek apakah string S menyatakan suaru area
misal : A4:B5 */
{
	char temp1[256] , temp2[256];
	boolean retval;
	
	s=UpperCase(s);
	sscanf(s.s , "%[^:]:%s" , temp1 , temp2);   

	retval = isCell(CharToString(temp1)) && isCell(CharToString(temp2));

	if(debug) printf("  isArea (%s) : ",s.s);
	if(debug) printf("%s\n",TF(retval));
	
	return retval;
}

void ParseArea (string s, string *PosStart, string *PosEnd)
/* melakukan parsing untuk mendapatkan posisi awal dan akhir dari suatu area
prekondisi : string s adalah suatu area */
{
	char temp1[256] , temp2[256];
	
	s=UpperCase(s);
	sscanf(s.s , "%[^:]:%s" , temp1 , temp2);   

	*PosStart = CharToString(temp1);
	*PosEnd	= CharToString(temp2);

}

void printArg (arguments a)
/* megeluarkan isi tabel arguments di layar */
{
	int i;
	for (i=0;i<a.nArg;i++){
		 printf("-    %02d.  %s\n",i,a.arg[i].s);
	}
}

string MakeFormula (string s)
/* membuat formula dari string S 
menghilangkan = di depan string S [kalau ada], membuang semua white space di dalam string */
{
		string tmp;
		boolean isString;
		int i;
		
		tmp.length=1;
		isString=0;

		if (s.s[0]!='=') {		
			s.length++;
			for(i=s.length;i>=1;i--) {
				s.s[i]=s.s[i-1];
				}
		}
		tmp.s[0] ='(';
		
		for (i=1;i<s.length;i++){
			if (s.s[i]==39){
				isString= !(isString);
				tmp.s[tmp.length]=s.s[i];
				tmp.length++;
			}
			else if ((s.s[i]!=' ')||(isString==1)){
				tmp.s[tmp.length]=s.s[i];
				tmp.length++;
				if ((s.s[i]==',')||(s.s[i]==')')
				||((s.s[i]=='<')&&(s.s[i+1]=='='))
				||((s.s[i]=='>')&&(s.s[i+1]=='='))
				||((s.s[i]=='!')&&(s.s[i+1]=='='))
				||(s.s[i]=='+')||(s.s[i]=='-')||(s.s[i]=='/')
				||(s.s[i]=='*')||(s.s[i]=='^')||(s.s[i]=='<')
				||(s.s[i]=='>')||(s.s[i]=='=')) {
					isString=0;
					}
			}
		}
		tmp.s[tmp.length]=')';
		tmp.length++;
		tmp.s[tmp.length]='\0';
		return tmp;
}

boolean isPrefFormula (string s)
/* mengecek apakah string s memiliki operator prefix pada posisi 1 stringnya
[or, and , not, mod, div , etc]*/
{
	boolean retval=0;
	if (	(IsStringEqSpec(GetSubString(s,0,4),CharToString("sum("))==1)||
		(IsStringEqSpec(GetSubString(s,0,8),CharToString("average("))==1)||
		(IsStringEqSpec(GetSubString(s,0,6),CharToString("count("))==1)||
		(IsStringEqSpec(GetSubString(s,0,6),CharToString("stdev("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("max("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("min("))==1)||
		(IsStringEqSpec(GetSubString(s,0,3),CharToString("if("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("sqr("))==1)||
		(IsStringEqSpec(GetSubString(s,0,5),CharToString("sqrt("))==1)||
		(IsStringEqSpec(GetSubString(s,0,7),CharToString("concat("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("mod("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("div("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("and("))==1)||
		(IsStringEqSpec(GetSubString(s,0,3),CharToString("or("))==1)||
		(IsStringEqSpec(GetSubString(s,0,4),CharToString("not("))==1)
	) {
		retval=1;
	}
	return retval;
}

arguments ParsePrefix (string f) 
/* mengembalikan hasil parsing ke dalam tabel arguments
[hanya memparse operator prefix, operator infix diabaikan]
prekondisi : s pasti memiliki 1 operator prefix didepan*/
{
	//printf("masuk ParsePrefix : %s\n",f.s);
	arguments tmp;
	tmp.nArg=0;
	int m=0,i=1;
	int ordo=0;

	while (i < f.length-1) {
		if (f.s[i]=='(') {
			ordo++;
		} else
		if (f.s[i]==')') {
			ordo--;
			}
			
		if 	(((ordo==1)&&(f.s[i]==','))
			||((ordo==1)&&(f.s[i]=='('))
			||((ordo==0)&&(f.s[i]==')'))
		)	{
			tmp.arg[tmp.nArg].s[m]='\0';
			tmp.arg[tmp.nArg].length=m;
			if (tmp.nArg>0)
				tmp.arg[tmp.nArg]=MakeFormula(tmp.arg[tmp.nArg]);
			
			tmp.nArg++;
			m=0;	
			}
		else {
			tmp.arg[tmp.nArg].s[m]=f.s[i];
			m++;
			}
		
		i++;
	}

	//printf("ordo %d \n", ordo);
	if(ordo==0) {return tmp;}
	else {
		tmp.nArg=0;
		return tmp;
	}
}

arguments ParseInfix (string f)
/* mengembalikan hasil parsing ke dalam tabel arguments
[hanya memparse operator infix, operator prefix diabaikan] */
{		
		arguments tmp;
		tmp.nArg=0;
		int m=0,i=1;
		int ordo=0;
		
		if((f.s[0]!='(')||(f.s[(f.length)-1]!=')')){
			//printf("s = %s\n",f.s);
			//printf("mestinya keluar disini\n");
			return tmp;}
		
		while (i < f.length) {
				if (((f.s[i]==')')||(f.s[i]=='\0'))&&(ordo==0)) {
						if(m>0){
							tmp.arg[tmp.nArg].s[m]='\0';
							tmp.arg[tmp.nArg].length=m;
							tmp.nArg++;
						}}
				else if ((f.s[i]=='-')&&((i==1)||(f.s[i-1]=='(')||(f.s[i-1]=='*')||
				(f.s[i-1]=='/')||(f.s[i-1]=='+')||(f.s[i-1]=='-')||(f.s[i-1]=='^'))) {
						//kasus minus
						tmp.arg[tmp.nArg].s[m]=f.s[i];
						m++;						
/*						if(f.s[i+1]=='(') {*/
/*								//misalkan kasus -(1+2*3) jadikan -1 *(1+2*3)*/
/*								tmp.arg[tmp.nArg] = CharToString("-1");*/
/*								tmp.nArg++;*/
/*								tmp.arg[tmp.nArg] = CharToString("*");*/
/*								tmp.nArg++;*/
/*								m=0;*/
/*								}*/
/*						else {*/
/*								tmp.arg[tmp.nArg].s[m]=f.s[i];*/
/*								m++;*/
/*								}*/
						}
				else if (f.s[i]=='(') {
						//open bracket
						ordo++;
						tmp.arg[tmp.nArg].s[m]=f.s[i];
						m++;
						}
				else if (f.s[i]==')') {
						//close bracket
						ordo--;
						tmp.arg[tmp.nArg].s[m]=f.s[i];
						m++;
						}
				else if ((((f.s[i]=='<')&&(f.s[i+1]=='='))||
					((f.s[i]=='>')&&(f.s[i+1]=='='))||
					((f.s[i]=='!')&&(f.s[i+1]=='=')))&&(ordo==0)) {
						//operator 2 karakter
						//logika : <= , >= , !=
						if(m>0){
								tmp.arg[tmp.nArg].s[m]='\0';
								tmp.arg[tmp.nArg].length=m;
								tmp.nArg++;
								}
						tmp.arg[tmp.nArg].s[0]=f.s[i];
						tmp.arg[tmp.nArg].s[1]=f.s[i+1];
						tmp.arg[tmp.nArg].s[2]='\0';
						tmp.arg[tmp.nArg].length=2;
						tmp.nArg++;
						m=0;
						i++;
						}
				else if (((f.s[i]=='+')||(f.s[i]=='-')||(f.s[i]=='/')||
					(f.s[i]=='*')||(f.s[i]=='^')||(f.s[i]=='<')
					||(f.s[i]=='>')||(f.s[i]=='='))&&(ordo==0)) {
						//operator 1 karakter
						//aritmatik : + - / * ^ 
						//logika : < > =
						if(m>0){
								tmp.arg[tmp.nArg].s[m]='\0';
								tmp.arg[tmp.nArg].length=m;
								tmp.nArg++;
								}
						tmp.arg[tmp.nArg].s[0]=f.s[i];
						tmp.arg[tmp.nArg].s[1]='\0';
						tmp.arg[tmp.nArg].length=1;
						tmp.nArg++;
						m=0;
						}
				else {
						tmp.arg[tmp.nArg].s[m]=f.s[i];
						m++;
						}
				//printf("i = %d , cChar = %c , ordo = %d , flength = %d\n ",i,f.s[i],ordo,f.length);
				//printf("nArg = %d\n",tmp.nArg);
				i++;
				}
		//printf("ordo=%d\n",ordo);
		//printf("nArg = %d\n",tmp.nArg);
		//printArg(tmp);
		return tmp;
}

string recursive_eval (string F, Sheet Sh)
/* melakukan proses evaluasi formula secara rekursif */
{		
		if (debug) printf("BARU MASUK REKURSI !! F= %s\n",F.s);
		
		//PSEUDOCONSTANT
		string ERROR;
		ERROR=CharToString("ERROR");
		
		arguments args;
		string temp,temp2,temp3;
		int rowA,rowB,tmpint;
		string colA,colB;
		

		
		int i;

		//printf("F adalah %s dengan length %d \n",F.s,F.length);
		int jj,ordo=0;
		for (jj=0;jj<F.length;jj++) {
			if (F.s[jj]=='(') {ordo++;}
			if (F.s[jj]==')') {ordo--;}
			//printf("c = %c, i = %d , ordo =%d \n",F.s[jj],jj,ordo);
			}
 	
		if (ordo!=0) {
			if (debug) printf("ERROR !! JUMLAH KURUNG BUKA DAN KURUNG TUTUP TDK SAMA\n");
			return ERROR;
			}
			
		if (F.s[0]==39){
			if (debug) printf("MEMILIKI TANDA PETIK, %s STRING !!\n",F.s);
			return F;
		}

		ordo=0; 	
		args = ParseInfix(F);
		
		if (debug) printf("Formula = %s ,nArg = %d\n",F.s,args.nArg);
		if (debug) printArg(args);
			
		if ((args.nArg==0)||(args.nArg==1)) {
			if (debug) printf("nArg = %d , F= %s\n",args.nArg,F.s);
			if (debug) printArg(args);
			
			if (args.nArg==0) {
				args.nArg=1;
				args.arg[0]=F;}	
			
			//printf("'mungkin' ngga bisa dieval lagi :  %s\n",F.s);
			if ((args.arg[0].s[0]=='(')&&(args.arg[0].s[(args.arg[0].length)-1]==')')) {
				if (debug) printf("ARGUMEN MASIH TERLETAK DIANTARA 2 KURUNG EVALUASI LAGI !! \n");
				return recursive_eval(args.arg[0] , Sh);				
			} else if (args.arg[0].s[0]=='!') {
				if (debug) printf("negasi\n");
				return NOT(recursive_eval(DeleteSubString(args.arg[0],0,1), Sh));
			} else if (args.arg[0].s[0]=='-') {
				if (debug) printf("minus \n");
				return MINUS(recursive_eval(DeleteSubString(args.arg[0],0,1), Sh));
			} else {
				if (debug) printf("ARGUMEN MERUPAKAN CELL/FORMULA PREFIX/VALUE\n");
				if (debug) printArg(args);
			
				if (isCell(args.arg[0])) {
					if (debug) printf("%s ADALAH ADDRESS DARI SUATU CELL\n",args.arg[0].s);
					GetXYChar(Sh ,UpperCase(args.arg[0]), &temp );
					if (temp.length!=0) 
						{return recursive_eval(MakeFormula(temp), Sh);}
					else
						{return temp;}
/*void GetXY (Sheet S, string Pos, address *Isi);*/
/* Mengambil alamat dari satu cell pada Spreadsheet dengan elemen berupa Isi pada posisi (Column,Row) */
/* Jika tidak ada cell dengan posisi (Column,Row) maka akan menghasilkan Nil */

				}
				else if (isPrefFormula(args.arg[0])) {
					//tinggal 1 argumen yang berupa operator prefix
					if (debug) printf("%s ADALAH FORMULA PREFIX\n",args.arg[0].s);
					
					args=ParsePrefix(MakeFormula(args.arg[0]));
					//printArg(args);

					/*----------------------------------------*/
					/*   FUNGSI - FUNGSI YANG MELIBATKAN AREA */
					/*----------------------------------------*/
					
					if (IsStringEqSpec(args.arg[0],CharToString("sum"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return SUM(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("average"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return AVERAGE(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("count"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return COUNT(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("stdev"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return STDEV(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("max"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return MAXS(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("min"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							temp3= recursive_eval(args.arg[1], Sh);
							if (isArea(temp3)) {
								temp3=UpperCase(temp3);
								ParseArea(temp3,&temp,&temp2);
								
								if (debug) printf("ATUR POSISI1 DAN POSISI2!!\n");
								if (debug) printf("TARUH ROWDANCOL TERKECIL DI TEMP DAN TERBESAR DI TEMP2 !!\n");
								
								PosToCR(temp, &colA, &rowA);
								PosToCR(temp2, &colB, &rowB);
								
								if ((rowA<1)||(rowB<1)) {
										if (debug) printf("ERROR OUT OF RANGE !!\n");
										return ERROR;}
								
								if (rowA > rowB) {tmpint=rowA;rowA=rowB;rowB=tmpint;}
								if (StringToBool(GT(colA,colB))) {temp=colA;colA=colB;colB=temp;}
								CRToPos(colA,rowA,&temp);
								CRToPos(colB,rowB,&temp2);
								
								return MINI(Sh, temp, temp2 );	
								}
							else {
								if (debug) printf("SETELAH ARGUMEN#2 DIEVAL MASIH BUKAN AREA\n");
								return ERROR;
							}
						}
					} else
					
					/*----------------------------------------*/
					/*   FUNGSI - FUNGSI ARIITMATIK PREFIX    */
					/*----------------------------------------*/
					
					if (IsStringEqSpec(args.arg[0],CharToString("sqr"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							return SQR(recursive_eval(args.arg[1], Sh));
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("sqrt"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							return SQRT(recursive_eval(args.arg[1], Sh));
						}
					}  else
					if (IsStringEqSpec(args.arg[0],CharToString("mod"))==1) {
						if (args.nArg!=3) {
							return ERROR;}
						else {
							return MOD(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh));
						}
					} else
					if (IsStringEqSpec(args.arg[0],CharToString("div"))==1) {
						if (args.nArg!=3) {
							return ERROR;}
						else {
							return DIV(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh));
						}
					}  else
					
					/*------------------------------------*/
					/*  FUNGSI - FUNGSI STRING PREFIX     */
					/*------------------------------------*/
					
					if (IsStringEqSpec(args.arg[0],CharToString("concat"))==1) {
						if (args.nArg!=3) {
							return ERROR;}
						else {
							return CONCAT(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh));
						}
					} else
					
					/*----------------------------------*/
					/*  FUNGSI - FUNGSI BOOLEAN PREFIX   /
					/*----------------------------------*/
					
					if (IsStringEqSpec(args.arg[0],CharToString("if"))==1) {
						if (args.nArg!=4) {
							return ERROR;}
						else {
							return IFCOND(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh),
								recursive_eval(args.arg[3], Sh)
								);
						}
					}  else
					if (IsStringEqSpec(args.arg[0],CharToString("and"))==1) {
						if (args.nArg!=3) {
							return ERROR;}
						else {
							return AND(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh));
						}
					}  else
					if (IsStringEqSpec(args.arg[0],CharToString("or"))==1) {
						if (args.nArg!=3) {
							return ERROR;}
						else {
							return OR(
								recursive_eval(args.arg[1], Sh),
								recursive_eval(args.arg[2], Sh));
						}
					}  else
					if (IsStringEqSpec(args.arg[0],CharToString("not"))==1) {
						if (args.nArg!=2) {
							return ERROR;}
						else {
							return NOT(recursive_eval(args.arg[1], Sh));
						}
					} else {
						if(debug) printf("ada fungsi yang blom direalisasi\n");
						return ERROR;
					}
				} 
				else {
					if(debug) printf("ini adalah VALUE !! RETURN %s !!!\n ",args.arg[0].s); 
					return(args.arg[0]);
				}
			}			
		} else {
			if(debug)printf("INI PERLU DIEVALUASI INFIX \n");
			if(debug)printArg(args);
			
			/*----------------------------------*/
			/*  LAKUKAN EVALUASI UNTUK PANGKAT  */
			/*----------------------------------*/
			
			i=0;
			while (i<args.nArg) {
				//printf("i = %d, nArg = %d \n",i,args.nArg);
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("^"))==1) {
					//printf("masuk pangkat\n");
					//printArg(args);
					replace3(i,
					POW(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}
				}
				i++;  			
			} 

			
			/*----------------------------------------*/
			/*  LAKUKAN EVALUASI UNTUK KALI DAN BAGI  */
			/*----------------------------------------*/
			
			i=0;
			while (i<args.nArg) {
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("*"))==1) {
					//printf("ketemu kali .. i = %d, nArg = %d \n",i,args.nArg);
					//printf("i = %d\n",i);
					replace3(i,
					MULTI(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					i=i-1;
					}}
				
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("/"))==1) {
					//printf("ketemu bagi gan !!,, i = %d, nArg = %d \n",i,args.nArg);
					//printArg(args);	
			
					//printf("i = %d\n",i);
					replace3(i,
					DIVIDE(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					i=i-1;
					//printArg(args);	
					}
				}
				i++;  			
			} 
			
			/*--------------------------------------------*/
			/*  LAKUKAN EVALUASI UNTUK TAMBAH DAN KURANG  */
			/*--------------------------------------------*/
			
			i=0;
			while (i<args.nArg) {
				//printf("i = %d, nArg = %d \n",i,args.nArg);
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("+"))==1) {
					//printArg(args);
					replace3(i,
					PLUS(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("-"))==1) {
					//printArg(args);
					replace3(i,
					MIN(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}
				}
				i++;  			
			}

			/*------------------------*/
			/*  BLOK OPERASI BOOLEAN  */
			/*------------------------*/
			
			i=0;
			while (i<args.nArg) {
				
				//printf("i = %d, nArg = %d \n",i,args.nArg);
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString(">"))==1) {
					//printArg(args);
					replace3(i,
					GT(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("<"))==1) {
					//printArg(args);
					replace3(i,
					LT(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString(">="))==1) {
					//printArg(args);
					replace3(i,
					GTOEQ(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("<="))==1) {
					//printArg(args);
					replace3(i,
					LTOEQ(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("="))==1) {
					//printArg(args);
					replace3(i,
					EQ(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				if((i>0)&&(i<(args.nArg-1))) {
					if (IsStringEqSpec(args.arg[i],CharToString("!="))==1) {
					//printArg(args);
					replace3(i,
					NEQ(recursive_eval(args.arg[i-1], Sh),recursive_eval(args.arg[i+1], Sh))
					,&args);
					//printArg(args);
					i=i-1;
					}}
				i++;  			
			} 
		}
		if(debug)printf("INI HASIL FINAL !!\n");
		if(debug)printArg(args);
		if ((args.nArg!=1)||(IsStringEqSpec(args.arg[0],CharToString("-nan"))==1)){
			if(debug)printf("ARGUMENTS > 1 TAPI TIDAK DAPAT DIEVAL LAGI !! :\n");
			return ERROR;}
		else {
			return args.arg[0];}
}

void replace3 (int x, string s, arguments *a) 
/* mereplace 3 argumen pada indeks x-1,x, dan x+1 tabel argumen a dengan 1 argumen s pa*/
{	
	int i,j,k;
	(*a).arg[x-1]=s;
	for(i=x;(i+2)<=(*a).nArg;i++)
		{
		(*a).arg[i]=(*a).arg[i+2];
		}
	(*a).nArg--;
	(*a).nArg--;
}
	
#endif
